#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <memory>

#include "Log.hpp"
#include "Mutex.hpp"
#include "Cond.hpp"
#include "Thread.hpp"

namespace SingleThreadPoolMouble
{
    using namespace LogMoudle;
    using namespace MutexMoudle;
    using namespace CondMoudle;
    using namespace ThreadMouble;
    
    using thread_t = std::shared_ptr<Thread>; // 对象必须在堆上构建
    const int Default_nums = 5;
    // T 为任务类型， 函数指针，任务类
    template <class T>
    class ThreadPool
    {
        ThreadPool(const ThreadPool<T> &) = delete;
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

        void HandleTask(std::string name)
        {
            LOG(LogLevel::NORMAL) << "线程" << name << "创建成功...";
            while (1)
            {
                T t;
                {
                    // 1. 取等任务
                    LockGuard lock(_mutex);
                    while (_taskq.empty() && _running)
                    {
                        _wait_num++;
                        _cond.Wait(_mutex);
                        _wait_num--;
                    }
                    // 到这要么有任务了，要么进程池不运行了。
                    if (_taskq.empty() && !_running)
                        break;

                    t = _taskq.front();
                    _taskq.pop();
                }
                // 2. 执行任务
                t(name); // 规定所有任务处理必须都重载了（）方法。
            }
            LOG(LogLevel::NORMAL) << "线程" << name << "退出...";
        }
        ThreadPool(int num = Default_nums)
            : _num(num), _wait_num(0), _running(false)
        {
            for (int i = 0; i < _num; i++)
            {
                _threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HandleTask, this, std::placeholders::_1)));
                LOG(LogLevel::NORMAL) << "构造线程 " << _threads.back()->Name() << "成功...";
            }
        }


    public:

        static ThreadPool* GetInstance()
        {
            if(instance==nullptr)
            {
                LockGuard  lock(mutex);
                if(instance==nullptr)
                {
                    LOG(LogLevel::NORMAL)<<"线程单例化完成...";
                    instance=new ThreadPool<T>();
                }
            }
                return instance;
        }

        void Equeue(T &&in) // 对临时变量的引用，避免了值拷贝的消耗
        {
            LockGuard lock(_mutex);
            {
                if (_running)
                {
                    _taskq.push(std::move(in));
                    LOG(LogLevel::NORMAL) << "新任务已入队...";
                    if (_wait_num > 0)
                        _cond.Notify();
                }
            }
        }

        void Start()
        {
            if (_running)
                return;
            _running = true; // 这里需不需要加锁？ 不需要，因为此时线程还没有启动，还有进程池主线程在
            for (int i = 0; i < _num; i++)
            {
                _threads[i]->Start();
                LOG(LogLevel::NORMAL) << "线程" << _threads[i]->Name() << "启动了...";
            }
        }
        void Wait()
        {
            for (int i = 0; i < _num; i++)
            {
                if (_threads[i]->GetJoin())
                {
                    _threads[i]->Join();
                    LOG(LogLevel::NORMAL) << "线程" << _threads[i]->Name() << "已回收...";
                }
            }
        }
        void Stop()
        {
            LockGuard lock(_mutex);
            if (_running)
            {
                _running = false; // 防止再有新的任务入列
                if (_wait_num > 0)
                    _cond.NotifyAll(); // 线程回收需要线程执行完毕 &&  历史上的任务执行完了
            }
        }
        ~ThreadPool()
        {
        }

    private:
        std::vector<thread_t> _threads; // 线程池
        int _num;                       // 线程池中的数量
        int _wait_num;                  // 线程池中等待的线程数量
        std::queue<T> _taskq;           // 任务队列

        bool _running; // 是否正在运行

        Mutex _mutex; // 线程之间互斥，线程与线程池之间也是互斥的
        Cond _cond;

        static ThreadPool<T>* instance;
        static Mutex mutex;   // 用于保护单例的锁

    };

    // 静态类变量，类内声明，类外初始化
    template<class T>
     ThreadPool<T>* ThreadPool<T>::instance=nullptr;
    template<class T>
    Mutex ThreadPool<T>::mutex;



}
